<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>极简ToDo</title>
  <style>
    /* 全局样式设置 */
    body {
        font-family: Arial, Helvetica, sans-serif; /* 设置字体 */
        background: #fafafa; /* 背景颜色 */
        margin: 0; /* 外边距归零 */
        padding: 0; /* 内边距归零 */
        display: flex; /* 使用弹性布局 */
        justify-content: center; /* 水平居中 */
    }
    
    /* 主容器样式 */
    .box {
        width: 320px; /* 固定宽度 */
        margin-top: 40px; /* 上边距 */
        background: #fff; /* 白色背景 */
        border: 1px solid #ddd; /* 边框 */
        border-radius: 6px; /* 圆角 */
        padding: 20px; /* 内边距 */
    }
    
    /* 标题样式 */
    h2 {
        text-align: center; /* 文字居中 */
        margin: 0 0 15px; /* 下边距 */
    }
    
    /* 输入区域样式 */
    .input-area {
        display: flex; /* 弹性布局 */
    }
    
    /* 输入框样式 */
    #taskInput {
        flex: 1; /* 占据剩余空间 */
        padding: 8px; /* 内边距 */
        font-size: 14px; /* 字体大小 */
        border: 1px solid #ccc; /* 边框 */
        border-radius: 4px 0 0 4px; /* 左侧圆角 */
        outline: none; /* 移除轮廓线 */
    }
    
    /* 添加按钮样式 */
    #addBtn {
        width: 60px; /* 固定宽度 */
        border: none; /* 无边框 */
        background: #007bff; /* 蓝色背景 */
        color: #fff; /* 白色文字 */
        border-radius: 0 4px 4px 0; /* 右侧圆角 */
        cursor: pointer; /* 手型光标 */
    }
    
    /* 按钮悬停效果 */
    #addBtn:hover {
        background: #0056b3; /* 深蓝色背景 */
    }
    
    /* 任务列表样式 */
    ul {
        list-style: none; /* 移除列表标记 */
        margin: 15px 0 0; /* 上边距 */
        padding: 0; /* 内边距归零 */
    }
    
    /* 单个任务项样式 */
    li {
        display: flex; /* 弹性布局 */
        justify-content: space-between; /* 两端对齐 */
        align-items: center; /* 垂直居中 */
        padding: 8px; /* 内边距 */
        border-bottom: 1px solid #f0f0f0; /* 底部边框 */
    }
    
    /* 最后一项任务无底部边框 */
    li:last-child {
        border: none; /* 无边框 */
    }
    
    /* 删除按钮样式 */
    .del {
        background: #dc3545; /* 红色背景 */
        color: #fff; /* 白色文字 */
        border: none; /* 无边框 */
        padding: 4px 8px; /* 内边距 */
        border-radius: 4px; /* 圆角 */
        cursor: pointer; /* 手型光标 */
        font-size: 12px; /* 较小字体 */
    }
    
    /* 删除按钮悬停效果 */
    .del:hover {
        background: #c82333; /* 深红色背景 */
    }
  </style>
</head>
<body>
  <div class="box">
    <h2>今日待办</h2>
    <div class="input-area">
      <!-- 任务输入框，autocomplete="off" 关闭自动完成 -->
      <input id="taskInput" placeholder="输入任务后回车" autocomplete="off" />
      <!-- 新增任务按钮 -->
      <button id="addBtn">新增</button>
    </div>
    <!-- 任务列表容器 -->
    <ul id="taskList"></ul>
  </div>
  <script>
    /* ===== 立即执行函数，避免污染全局作用域 ===== */
    ;(function(){
      /* ---------- 3.1 工具函数 ---------- */
      
      /**
       * 从本地存储加载任务列表
       * @returns {Array} 任务数组，解析失败时返回空数组
       */
      function loadTasks(){
        try{
          // 从localStorage获取'td'键的值，解析为JSON，如果为空则返回空数组
          return JSON.parse(localStorage.getItem('td')) || []
        }catch(e){
          // 如果解析过程出现异常（如数据格式错误），返回空数组
          console.error('加载任务失败:', e)
          return []
        }
      }
      
      /**
       * 将任务数组保存到本地存储
       * @param {Array} arr - 要保存的任务数组
       */
      function saveTasks(arr){
        try {
          // 将数组转换为JSON字符串并存储到localStorage的'td'键中
          localStorage.setItem('td', JSON.stringify(arr))
        } catch(e) {
          // 处理可能的异常（如存储空间不足或浏览器隐私模式）
          console.error('保存任务失败:', e)
          // 这里可以添加用户提示，例如alert('保存失败，请检查浏览器设置')
        }
      }
      
      /**
       * 生成唯一ID
       * 使用36进制是为了生成更短的唯一ID
       * 36进制（0-9,a-z）比10进制能表示更多信息，用更少字符表达相同数值
       * @returns {string} 唯一标识符
       */
      function genId(){
        // Date.now()获取当前时间戳，转换为36进制字符串
        // Math.random()生成随机数，转换为36进制并截取部分字符
        return Date.now().toString(36) + Math.random().toString(36).slice(2,6)
      }

      /* ---------- 3.2 获取DOM元素 ---------- */
      const taskInput = document.getElementById('taskInput') // 任务输入框
      const addBtn    = document.getElementById('addBtn')    // 添加按钮
      const taskList  = document.getElementById('taskList')  // 任务列表容器

      /* ---------- 3.3 数据层 ---------- */
      let tasks = loadTasks()   // 从本地存储加载初始任务数据

      /* ---------- 3.4 渲染函数 ---------- */
      /**
       * 渲染任务列表到页面
       */
      function render(){
        // 清空列表容器，准备重新渲染
        taskList.innerHTML = ''
        
        // 检查是否有任务
        if (tasks.length === 0) {
          // 如果没有任务，显示提示信息
          taskList.innerHTML = '<li style="justify-content: center; color: #999;">暂无任务</li>'
          return
        }
        
        // 遍历所有任务，创建对应的DOM元素
        tasks.forEach(item => {
          // 创建列表项元素
          const li = document.createElement('li')
          // 设置列表项HTML内容
          li.innerHTML = `
            <span>${item.text}</span>
            <button class="del" data-id="${item.id}">删除</button>
          `
          // 将列表项添加到任务列表中
          taskList.appendChild(li)
        })
      }

      /* ---------- 3.5 新增任务 ---------- */
      /**
       * 添加新任务到列表
       */
      function addTask(){
        // 获取输入框的值并去除首尾空格
        const txt = taskInput.value.trim()
        
        // 判断输入是否为空
        if(!txt) {
          // 如果为空，可以给用户提示（可选）
          // alert('请输入任务内容')
          return // 直接返回，不执行后续操作
        }
        
        // 将新任务添加到任务数组
        tasks.push({ 
          id: genId(),   // 生成唯一ID
          text: txt      // 任务文本
        })
        
        // 保存更新后的任务数组到本地存储
        saveTasks(tasks)
        
        // 清空输入框
        taskInput.value = ''
        
        // 重新渲染任务列表
        render()
      }

      /* ---------- 3.6 删除任务 ---------- */
      /**
       * 处理删除任务操作
       * @param {Event} e - 事件对象
       */
      function delTask(e){
        // 事件委托中的过滤判断：确保只有点击带有"del"类的元素（删除按钮）才会触发删除操作
        if(!e.target.classList.contains('del')) return
        
        // 获取要删除的任务ID（存储在按钮的data-id属性中）
        const id = e.target.dataset.id
        
        // 过滤任务数组，移除对应ID的任务
        tasks = tasks.filter(item => item.id !== id)
        
        // 保存更新后的任务数组到本地存储
        saveTasks(tasks)
        
        // 重新渲染任务列表
        render()
      }

      /* ---------- 3.7 绑定事件处理器 ---------- */
      // 为添加按钮绑定点击事件
      addBtn.addEventListener('click', addTask)
      
      // 为输入框绑定键盘事件（回车键添加任务）
      taskInput.addEventListener('keyup', e => {
        if(e.key === 'Enter') addTask()
      })
      
      // 为任务列表绑定点击事件（使用事件委托处理删除操作）
      taskList.addEventListener('click', delTask)

      /* ---------- 3.8 首次渲染 ---------- */
      render() // 页面加载完成后立即渲染任务列表
    })() // 立即执行函数结束
  </script>
</body>
</html>